package com.gitee.luosl.cola.stream;

import com.gitee.luosl.cola.lang.AbstractIterator;
import com.gitee.luosl.cola.lang.function.checked.*;
import com.gitee.luosl.cola.match.Match;
import com.gitee.luosl.cola.lang.Tuple;
import com.gitee.luosl.cola.lang.Tuple2;
import com.gitee.luosl.cola.match.cases.ICase;

import java.util.*;
import java.util.function.*;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;

public final class GeneralStreamWrapper<T> extends AbstractStreamWrapper<T> {

    public GeneralStreamWrapper<T> parallel(){
        return wrap(getStream().parallel());
    }

    GeneralStreamWrapper(Stream<T> stream) {
        super(stream);
    }

    private <U> GeneralStreamWrapper<U> wrap(Stream<U> stream){
        return new GeneralStreamWrapper<>(stream);
    }

    public GeneralStreamWrapper<T> filter(Predicate<? super T> predicate) {
        return wrap(getStream().filter(predicate));
    }

    public GeneralStreamWrapper<T> filterTry(CheckedPredicate<? super T> predicate) {
        return filter(predicate.toPredicate());
    }

    @SafeVarargs
    public final <U, R> GeneralStreamWrapper<R> map(ICase<? extends T, ? extends U, ? extends R>... cases) {
        return map(value -> Match.of(value).matchCatch(cases));
    }

    public <R> GeneralStreamWrapper<R> map(Function<? super T, ? extends R> mapper) {
        return wrap(getStream().map(mapper));
    }

    public <R> GeneralStreamWrapper<R> mapTry(CheckedFunction<? super T, ? extends R> mapper) {
        return wrap(getStream().map(mapper.toFunction()));
    }

    public IntStream mapToInt(ToIntFunction<? super T> mapper){
        return getStream().mapToInt(mapper);
    }

    @SafeVarargs
    public final <U> IntStream mapToInt(ICase<? extends T, ? extends U, Integer>... cases){
        return mapToInt(i -> Match.of(i).matchCatch(cases));
    }

    public IntStream mapToIntTry(CheckedToIntFunction<? super T> mapper){
        return getStream().mapToInt(mapper.asToIntFunction());
    }

    public LongStream mapToLong(ToLongFunction<? super T> mapper){
        return getStream().mapToLong(mapper);
    }

    @SafeVarargs
    public final <U> LongStream mapToLong(ICase<? extends T, ? extends U, Long>... cases){
        return mapToLong(i -> Match.of(i).matchCatch(cases));
    }

    public LongStream mapToLongTry(CheckedToLongFunction<? super T> mapper){
        return getStream().mapToLong(mapper.asToLongFunction());
    }

    public DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper){
        return getStream().mapToDouble(mapper);
    }

    @SafeVarargs
    public final <U> DoubleStream mapToDouble(ICase<? extends T, ? extends U, Double>... cases){
        return mapToDouble(i -> Match.of(i).matchCatch(cases));
    }

    public DoubleStream mapToDoubleTry(CheckedToDoubleFunction<? super T> mapper){
        return getStream().mapToDouble(mapper.asToDoubleFunction());
    }

    public <R> GeneralStreamWrapper<R> flatMap(Function<? super T, ? extends GeneralStreamWrapper<? extends R>> mapper) {
        return wrap(getStream().flatMap(data -> mapper.apply(data).getStream()));
    }

    public <R> GeneralStreamWrapper<R> flatMapTry(CheckedFunction<? super T, ? extends GeneralStreamWrapper<? extends R>> mapper) {
        return wrap(getStream().flatMap(data -> mapper.toFunction().apply(data).getStream()));
    }

    @SafeVarargs
    public final <U, R> GeneralStreamWrapper<R> flatMap(ICase<? extends T, ? extends U, ? extends GeneralStreamWrapper<? extends R>>... cases) {
        return flatMap(value -> Match.of(value).matchCatch(cases));
    }

    public GeneralStreamWrapper<T> distinct() {
        return wrap(getStream().distinct());
    }

    public GeneralStreamWrapper<T> sorted() {
        return wrap(getStream().sorted());
    }

    public GeneralStreamWrapper<T> sorted(Comparator<? super T> comparator) {
        return wrap(getStream().sorted(comparator));
    }

    public GeneralStreamWrapper<T> peek(Consumer<? super T> action) {
        return wrap(getStream().peek(action));
    }

    public GeneralStreamWrapper<T> peekTry(CheckedConsumer<? super T> action) {
        return peek(action.toConsumer());
    }

    public GeneralStreamWrapper<T> limit(long maxSize) {
        return wrap(getStream().limit(maxSize));
    }

    public GeneralStreamWrapper<T> skip(long n) {
        return wrap(getStream().skip(n));
    }

    public <K, V> EntryStreamWrapper<K, V> mapToEntry(Function<T, Tuple2<K, V>> mapper){
        return StreamWrapper.wrapEntry(getStream().map(mapper));
    }

    public <K, V> EntryStreamWrapper<K, V> mapToEntry(Function<T ,K> keyMapper, Function<T, V> valueMapper){
        return mapToEntry(item -> Tuple.of(keyMapper.apply(item), valueMapper.apply(item)));
    }

    public <K, V> EntryStreamWrapper<K, V> mapToEntryTry(CheckedFunction<T, Tuple2<K, V>> mapper){
        return StreamWrapper.wrapEntry(getStream().map(mapper.toFunction()));
    }

    public <K, V> EntryStreamWrapper<K, V> mapToEntryTry(CheckedFunction<T ,K> keyMapper, CheckedFunction<T, V> valueMapper){
        return mapToEntryTry(item -> Tuple.of(keyMapper.apply(item), valueMapper.apply(item)));
    }

    @SafeVarargs
    public final <U, K, V> EntryStreamWrapper<K, V> mapToEntry(ICase<? extends T, ? extends U, ? extends Tuple2<K, V>>... cases){
        return StreamWrapper.wrapEntry(getStream().map(item -> Match.of(item).matchCatch(cases)));
    }

    private GeneralStreamWrapper<T> sortByAsc(Supplier<Comparator<T>> supplier, boolean nullFirst){
        Comparator<T> comparator = supplier.get();
        if(nullFirst){
            comparator = Comparator.nullsFirst(comparator);
        }else{
            comparator = Comparator.nullsLast(comparator);
        }
        return sorted(comparator);
    }

    /**
     * 根据指定方式进行排序
     * 例如:
     * GeneralStreamWrapper<Integer> stream = StreamWrapper.of(2, 1, 3, 4, null);
     * List<Integer> s = stream.sortBy(i -> i, true).toList();
     * System.out.println(s);
     * 输出:
     * [null, 1, 2, 3, 4]
     * @param orderExtractor 排序字段抽取
     * @param nullFirst null 值是否放在头部
     * @param <R> 排序字段类型
     * @return 排序后的 streamWrapper
     */
    public <R extends Comparable<R>> GeneralStreamWrapper<T> sortByAsc(Function<T, R> orderExtractor, boolean nullFirst) {
       return sortByAsc(() -> Comparator.comparing(orderExtractor), nullFirst);
    }

    public <R extends Comparable<R>> GeneralStreamWrapper<T> sortByAsc(Function<T, R> orderExtractor) {
        return sortByAsc(() -> Comparator.comparing(orderExtractor), true);
    }

    public <R> GeneralStreamWrapper<T> sortByAsc(Function<T, R> orderExtractor, Comparator<R> byComparator){
        return sortByAsc(orderExtractor, byComparator, true);
    }

    public <R> GeneralStreamWrapper<T> sortByAsc(Function<T, R> orderExtractor, Comparator<R> byComparator, boolean nullFirst) {
        return sortByAsc(() -> Comparator.comparing(orderExtractor, byComparator), nullFirst);
    }

    /**
     * 根据指定方式进行倒排序
     * 例如:
     * GeneralStreamWrapper<Integer> stream = StreamWrapper.of(2, 1, 3, 4, null);
     * List<Integer> s = stream.sortBy(i -> i, true).toList();
     * System.out.println(s);
     * 输出:
     * [null, 4, 3, 2, 1]
     * @param orderExtractor 排序字段抽取
     * @param nullFirst null 值是否放在头部
     * @param <R> 排序字段类型
     * @return 排序后的 streamWrapper
     */
    public <R extends Comparable<R>> GeneralStreamWrapper<T> sortByDesc(Function<T, R> orderExtractor, boolean nullFirst){
        return sortByAsc(() -> Comparator.comparing(orderExtractor).reversed(), nullFirst);
    }

    public <R extends Comparable<R>> GeneralStreamWrapper<T> sortByDesc(Function<T, R> orderExtractor) {
        return sortByAsc(() -> Comparator.comparing(orderExtractor).reversed(), false);
    }

    public <R> GeneralStreamWrapper<T> sortByDesc(Function<T, R> orderExtractor, Comparator<R> byComparator) {
        return sortByDesc(orderExtractor, byComparator, false);
    }

    public <R> GeneralStreamWrapper<T> sortByDesc(Function<T, R> orderExtractor, Comparator<R> byComparator, boolean nullFirst) {
        return sortByAsc(() -> Comparator.comparing(orderExtractor, byComparator).reversed(), nullFirst);
    }

    /**
     * 根据指定条件对 stream 进行去重
     * GeneralStreamWrapper<Integer> stream = StreamWrapper.of(2, 1, 2, 4, null);
     * List<Integer> r = stream.distinctBy(i -> i).toList();
     * System.out.println(r);
     * 输出:
     * [2, 1, 4, null]
     * @param byExtractor 去重字段抽取
     * @param <K> 去重字段类型
     * @return 去重后的 streamWrapper
     */
    public <K> GeneralStreamWrapper<T> distinctBy(Function<T, K> byExtractor){
        return distinctBy(byExtractor, this::wrap);
    }

    public GeneralStreamWrapper<T> filterNot(Predicate<? super T> predicate){
        return filter(predicate.negate());
    }

    public GeneralStreamWrapper<T> takeWhile(Predicate<? super T> predicate) {

        final AbstractIterator<T> itr = iterator();

        if(!itr.hasNext()){
            return this;
        }

        return new AbstractIterator<T>() {

            T next = itr.next();

            @Override
            public boolean hasNext() {
                return null != next && !predicate.test(next);
            }

            @Override
            protected T getNext() {
                T temp = next;
                if(itr.hasNext()){
                    next = itr.next();
                }else{
                    next = null;
                }
                return temp;
            }
        }.streamWrapper();
    }

    public GeneralStreamWrapper<T> dropWhile(Predicate<? super T> predicate) {
        AbstractIterator<T> itr = iterator();
        boolean needStop = false;
        while (itr.hasNext() && !needStop){
            T data = itr.next();
            if(predicate.test(data)){
                needStop = true;
            }
        }
        return itr.streamWrapper();
    }

    @SafeVarargs
    public final <U> void forEach(ICase<? extends T, ? extends U, ?> ...cases){
        forEach(item -> Match.of(item).matchCatch(cases));
    }

    @SafeVarargs
    public final <U> GeneralStreamWrapper<T> peek(ICase<? extends T, ? extends U, ?> ...cases) {
        return peek(item -> Match.of(item).matchCatch(cases));
    }

    public GeneralStreamWrapper<T> reWrap(){
        return StreamWrapper.wrap(toList());
    }


}
